Skip to content

feat(chalice): Add span streaming support to Chalice integration#6503

Draft
ericapisani wants to merge 9 commits into
masterfrom
py-2312-migrate-chalice
Draft

feat(chalice): Add span streaming support to Chalice integration#6503
ericapisani wants to merge 9 commits into
masterfrom
py-2312-migrate-chalice

Conversation

@ericapisani

@ericapisani ericapisani commented Jun 4, 2026

Copy link
Copy Markdown
Member

Add span streaming support behind the trace_lifecycle=stream experiment flag.
When enabled, start a segment span with Lambda/FaaS attributes for both
HTTP view functions and event source handlers instead of setting a
transaction name on the scope.

Also adds aws_lambda to CLOUD_PLATFORM constants.

Contains some duplication with #6498 since it's an AWS lambda framework.

Fixes PY-2312
Fixes #6010

Add span streaming support behind the trace_lifecycle=stream experiment flag.
When enabled, start a segment span with Lambda/FaaS attributes for both
HTTP view functions and event source handlers instead of setting a
transaction name on the scope.

Also adds aws_lambda to CLOUD_PLATFORM constants.

Fixes PY-2312
Fixes #6010
@linear-code

linear-code Bot commented Jun 4, 2026

Copy link
Copy Markdown

PY-2312

@ericapisani

Copy link
Copy Markdown
Member Author

bugbot run
@sentry review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 208cf35. Configure here.

Comment thread sentry_sdk/integrations/chalice.py Outdated
Comment thread sentry_sdk/integrations/chalice.py Outdated
Comment on lines +204 to +206
invoked_arn = aws_context.invoked_function_arn
split_invoked_arn = invoked_arn.split(":")
aws_region = split_invoked_arn[3] if len(split_invoked_arn) > 3 else "unknown"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although AWS sets this value and it's unlikely to be malformed, these extra guards were added to ensure that if it were, we don't crash the user's application

Comment thread sentry_sdk/integrations/chalice.py Outdated
Comment thread tests/integrations/chalice/test_chalice.py
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Codecov Results 📊

89425 passed | ⏭️ 6013 skipped | Total: 95438 | Pass Rate: 93.7% | Execution Time: 307m 19s

📊 Comparison with Base Branch

Metric Change
Total Tests 📈 +14
Passed Tests 📈 +14
Failed Tests
Skipped Tests

All tests are passing successfully.

✅ Patch coverage is 94.12%. Project has 2394 uncovered lines.
✅ Project coverage is 89.81%. Comparing base (base) to head (head).

Files with missing lines (1)
File Patch % Lines
sentry_sdk/integrations/chalice.py 94.12% ⚠️ 3 Missing and 6 partials
Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
+ Coverage    89.80%    89.81%    +0.01%
==========================================
  Files          192       192         —
  Lines        23460     23501       +41
  Branches      8062      8076       +14
==========================================
+ Hits         21069     21107       +38
- Misses        2391      2394        +3
- Partials      1328      1334        +6

Generated by Codecov Action

@ericapisani ericapisani marked this pull request as ready for review June 4, 2026 18:18
@ericapisani ericapisani requested a review from a team as a code owner June 4, 2026 18:18
Comment thread sentry_sdk/integrations/chalice.py Outdated
Comment on lines -43 to -54
try:
return ChaliceEventSourceHandler.__call__(self, event, context)
except Exception:
exc_info = sys.exc_info()
event, hint = event_from_exception(
exc_info,
client_options=client.options,
mechanism={"type": "chalice", "handled": False},

if has_span_streaming_enabled(client.options):
span = sentry_sdk.traces.start_span(
name=context.function_name,
parent_span=None,
attributes=_get_lambda_span_attributes(context),
)
sentry_sdk.capture_event(event, hint=hint)
client.flush()
reraise(*exc_info)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to do anything here, just leave as is -- this code doesn't do any tracing so we don't need to change it

The set of spans we're creating should be the same as in the legacy path, we don't want any new spans when streaming

Comment thread sentry_sdk/integrations/chalice.py Outdated
Comment on lines +122 to +130
span = sentry_sdk.traces.start_span(
name=aws_context.function_name,
parent_span=None,
attributes={
**_get_lambda_span_attributes(aws_context),
**header_attrs,
**additional_attrs,
},
)

@sentrivana sentrivana Jun 5, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also a new span compared to the legacy path -- please remove

As I understand, this integration is built on top of the AWS Lambda integration similar to e.g. Flask and WSGI? In that case, the pattern is usually that the parent integration creates the transaction/segment encompassing the whole request-response cycle, and the child integration then augments it with info specific to the child integration (e.g. better transaction name and source). The child integration may also create its own spans (e.g. for middlewares, DB queries etc.), but it shouldn't double-instrument the same thing as the top level segment

All of this is to say -- if we don't explicitly create a span in the legacy path, we shouldn't do it in span streaming either

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this integration specifically, we seem to just want to augment whatever transaction is currently running with the same data as in the AWS Lambda integration.

The question for me is, does this integration even make sense standalone? Because if not, then we don't need to do any sort of post-enrichment here, as it'll already have happened in the AWS Lambda integration. Otherwise, we need to duplicate the enriching logic, but apply it to the current segment instead of creating a new span.

…led and where the Chalice integration is running on its own
Removes the creation of new spans but instead updates the segment of the
current span should one be present (this happens if the AWS Lambda
integration is also enabled and would be what creates the initial span).
Comment on lines +120 to +129
try:
return view_function(**function_args)
except Exception as exc:
if isinstance(exc, ChaliceViewError):
raise
exc_info = sys.exc_info()
if segment:
segment.status = SpanStatus.ERROR.value
sentry_event, hint = event_from_exception(
exc_info,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The Chalice integration fails to create a transaction with span streaming enabled if a segment doesn't already exist, resulting in lost transaction context for errors.
Severity: MEDIUM

Suggested Fix

Within the if has_span_streaming_enabled(client.options): block, add an else case to handle when type(current_span) is StreamedSpan is false. This new branch should create a transaction to ensure that transaction context is always established, mirroring the behavior of the non-streaming path.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: sentry_sdk/integrations/chalice.py#L120-L129

Potential issue: When span streaming is enabled in the Chalice integration, but no
preceding integration (like AWS Lambda) has created a segment, the system fails to
create a new transaction or span. This occurs because the code explicitly checks if
`type(current_span) is StreamedSpan`, and if this check fails (e.g., `current_span` is
`None` or `NoOpStreamedSpan`), there is no fallback logic to create a transaction.
Unlike the non-streaming path which sets a transaction name on the scope, this path does
nothing, causing any captured errors to lack transaction context.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, we don't want to create a new streamed span since no spans were created to begin with within the integration

return app


def test_span_streaming_existing_span(

@sentry-warden sentry-warden Bot Jun 11, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No test for span streaming when no outer Lambda segment exists

Both new streaming tests always wrap the request in an outer start_span, so the code path where has_span_streaming_enabled is True but type(current_span) is StreamedSpan is False (standalone Chalice with streaming, no AWS Lambda integration) is never exercised — in that path segment stays None, no span is created, and no transaction name is set, silently dropping all tracing data.

Evidence
  • In chalice.py lines 89-91, when has_span_streaming_enabled is True and type(current_span) is StreamedSpan is False, segment remains None and the code falls through directly to view_function(**function_args) — no span is started and scope.set_transaction_name is not called.
  • Both test_span_streaming_existing_span (line 200) and test_span_streaming_existing_span_error (line 224) always enter the request inside a sentry_sdk.traces.start_span(...) block, so get_current_span() always returns a StreamedSpan and the segment = None branch is never hit.
  • _make_span_streaming_app is only used by these two tests; no fixture or test exercises the streaming path without an enclosing segment.
  • The implementation silently discards tracing data in this case rather than creating a new segment span, contradicting the PR description ('start a segment span with Lambda/FaaS attributes for both HTTP view functions and event source handlers').
Also found at 1 additional location
  • sentry_sdk/integrations/chalice.py:130-137

Identified by Warden code-review, find-bugs · L2A-HR5

@ericapisani ericapisani marked this pull request as draft June 11, 2026 19:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Migrate chalice to span first

2 participants